<template>
  <div id="mountNode_readOnly" ref="G6C" @contextmenu="() => false">
  </div>
</template>
<script lang="ts" setup>

import G6 from '@antv/g6';
import { ref, onMounted, nextTick, watch, onUnmounted } from 'vue'
import type { ModelConfig, IGroup, IShape } from '@antv/g6'
import { randomWord } from '@/utils/common'

import { useRoute } from "vue-router";
import { message } from 'ant-design-vue';
import request from '@/api/index';
// ts
interface propoties {
  [propName: string]: any;
}
//props
const props = defineProps({
  workflowInstanceChat: {
    type: Object,
    default: {}
  }
})

//emit
const emits = defineEmits(['getCurrentNode', 'checkFlowEdgeConfig'])
//data
//路由信息
const routeParams: propoties = useRoute().query;
const flow_data = ref({
  "nodes": [

  ],
  "edges": [

  ],
  "combos": []
});
const anchorAttrs = {
  x: 0,
  y: 0,
  r: 4,
  stroke: '#1F6DED',
  fill: '#ffffff',
  fillOpacity: 0,
  strokeOpacity: 0,
  lineWidth: 1,
  cursor: 'crosshair',
  type: 'anchor',
  anchorType: 'in',
  anchorIndex: 0,
  shadowBlur: 2,
  shadowColor: '#999999'
};
const anchors = [
  {
    x: -80,
    y: 0,
    anchorIndex: 0
  },
  {
    x: 0,
    y: 24,
    anchorIndex: 1
  },
  {
    x: 80,
    y: 0,
    anchorIndex: 2
  },
  {
    x: 0,
    y: -24,
    anchorIndex: 3
  },

];
let graph: any = ref('');
let currentNode = ref<propoties>({}); // 当前节点或线的数据
let edge = ref<any>(null);
let addingEdge = ref<Boolean>(false);
let movingEdge = ref<Boolean | string>(false);
let selectItemId = ref<propoties>({});
let mode = ref<string>('readonly');
let nodeTypes = ref<string[]>(['begin', 'audit', 'end', 'line', 'beginline']);
const G6C = ref(null);
const node_dragging = ref<Boolean>(true);
watch(() => props.workflowInstanceChat, (newVal, oldVal) => {
  if (newVal != oldVal) {
    getWorkFlowData(newVal);
  }
})
watch(() => mode.value, (newVal, oldVal) => {
  if (newVal != oldVal) {
    graph.value.setMode(newVal);
  }
})
onMounted(() => {
  //G6Polyline();
  let Node = document.getElementById('mountNode_readOnly');
  if (Node) {
    Node.addEventListener('contextmenu', (e) => {
      e.stopPropagation();
      e.preventDefault();
      return false;
    })
  }
  //getWorkFlowData()
})
onUnmounted(() => {
  //graph.value.destroyed()
})
// 获取已上传的流程图数据
const getWorkFlowData = (data: propoties) => {

  let lines = data.lineViews;
  let nodes = data.nodeViews;
  lines.forEach((item: propoties) => {
    let lineCode = item.lineCode;
    item.lineCode = item.id;
    item.id = lineCode
  })
  nodes.forEach((item: propoties) => {
    let nodeCode = item.nodeCode;
    item.nodeCode = item.id; // id这属性后台要用;
    item.id = nodeCode;
  })
  flow_data.value.edges = lines;
  flow_data.value.nodes = nodes;
  init();
}
defineExpose({ G6C, graph, selectItemId, currentNode });
G6.registerNode(
  'beginNode',
  {
    drawShape(cfg?: ModelConfig | undefined, group?: propoties) {
      if (cfg && group) {
        const rect = group.addShape('rect', {
          attrs: {
            x: -25,
            y: -25,
            width: 50,
            height: 50,
            radius: 25,
            stroke: '#1F6DED',
            fill: '#1F6DED',
            lineWidth: 1,
          },
          draggable: true,
          name: 'rect-shape',
        });
        let anchors = [
          {
            x: -25,
            y: 0,
            anchorIndex: 0
          },
          {
            x: 0,
            y: 25,
            anchorIndex: 1
          },
          {
            x: 25,
            y: 0,
            anchorIndex: 2
          },
          {
            x: 0,
            y: -25,
            anchorIndex: 3
          },
        ]
        anchors.forEach(a => {
          if (group) {
            group.addShape('circle', {
              attrs: {
                ...anchorAttrs,
                ...a
              },
              className: 'anchor'
            })
          }

        })
        const name = cfg.name || '';
        //文字
        group.addShape('text', {
          attrs: {
            y: 0,
            x: 0,
            textAlign: 'center',
            textBaseline: 'middle',
            text: cfg.label,
            fill: '#fff',
          },
          draggable: true,
        });
        return rect
      }
    },
    getAnchorPoints(cfg) {
      return [
        [0.5, 0.5],
      ]
    },
    setState: (name, value, item) => {
      // var shape = item.get('keyShape')
      if (item) {
        const group = item.getContainer()
        const childrens = group.get('children')
        graph.value.setAutoPaint(false)
        const id = item.getModel().id
        const { source, target } = currentNode.value
        const isRelease = source === id || target === id;
        if ((name === 'hover' || name === 'selected') && (!isRelease || movingEdge.value)) {
          if (value) {
            // 显示节点上的锚点
            childrens.forEach((shape: any) => {
              if (shape.get('className') === 'anchor') {
                shape.attr('fillOpacity', 1)
                shape.attr('strokeOpacity', 1)
                shape.attr('cursor', 'crosshair')
              }
            })
          } else {
            // 隐藏节点上的锚点
            childrens.forEach((shape: any) => {
              if (shape.get('className') === 'anchor') {
                shape.attr('fillOpacity', 0)
                shape.attr('strokeOpacity', 0)
                shape.attr('cursor', 'default')
              }
            })
          }
        }
        graph.value.setAutoPaint(true)
      }
    }
  },
);
G6.registerNode('auditNode', {
  drawShape(cfg?: ModelConfig | undefined, group?: propoties) {
    if (cfg && group) {
      const rect = group.addShape('rect', {
        attrs: {
          x: -80,
          y: -24,
          width: 160,
          height: 48,
          radius: 5,
          stroke: '#9CCCFF',
          fill: 'l(0) 0:#EDF7FF 1:#EDF7FF',
          lineWidth: 2,
        },
        name: 'rect-shape',
        draggable: true,
      });
      anchors.forEach(a => {
        if (group) {
          group.addShape('circle', {
            attrs: {
              ...anchorAttrs,
              ...a
            },
            className: 'anchor'
          })
        }

      })
      const name = cfg.name || '';
      const text = group.addShape('text', {
        attrs: {
          y: 0,
          x: 0,
          textAlign: 'center',
          textBaseline: 'middle',
          text: cfg.label,
          fill: '#565A5D',
        },
        draggable: true,
      });
      text.set('capture', false);
      return rect
    }

  },
  getAnchorPoints(cfg) {
    return [
      [0.5, 0.5],
    ]
  },
  setState: (name, value, item) => {
    // var shape = item.get('keyShape')
    if (item) {
      const group = item.getContainer()
      const childrens = group.get('children');
      graph.value.setAutoPaint(false)
      const id = item.getModel().id
      const { source, target } = currentNode.value
      const isRelease = source === id || target === id;
      if ((name === 'hover')) {
        if (value) {
          // 显示节点上的锚点
          childrens.forEach((shape: any) => {
            if (shape.get('className') === 'anchor') {
              shape.attr('fillOpacity', 1)
              shape.attr('strokeOpacity', 1)
              shape.attr('cursor', 'crosshair')
            }
          })
        } else {
          // 隐藏节点上的锚点
          childrens.forEach((shape: any) => {
            if (shape.get('className') === 'anchor') {
              shape.attr('fillOpacity', 0)
              shape.attr('strokeOpacity', 0)
              shape.attr('cursor', 'default')
            }
          })
        }
      }
      if (name === 'click') {
        const shape = group.get('children')[0];
        if (value) {

          shape.attr('stroke', '#1f6DED');
        } else {
          shape.attr('stroke', '#9CCCFF');
        }

      }
      if (name == 'error') {
        const shape = group.get('children')[0];
        if (value) {
          shape.attr('stroke', 'red');

        } else {
          shape.attr('stroke', '#9CCCFF');
        }
      }
      graph.value.setAutoPaint(true)
    }

  },
}, 'beginNode');
G6.registerNode('endNode', {
  drawShape(cfg?: propoties, group?: propoties) {
    if (cfg && group) {
      const rect = group.addShape('rect', {
        attrs: {
          x: -38,
          y: -24,
          width: 76,
          height: 48,
          radius: 24,
          stroke: '#E2E2E2',
          fill: '#fff',
          lineWidth: 2,
        },
        draggable: true,
      })
      let anchors = [
        {
          x: -38,
          y: 0,
          anchorIndex: 0
        },
        {
          x: 0,
          y: 24,
          anchorIndex: 1
        },
        {
          x: 38,
          y: 0,
          anchorIndex: 2
        },
        {
          x: 0,
          y: -24,
          anchorIndex: 3
        },

      ];
      anchors.forEach(a => {
        group.addShape('circle', {
          attrs: {
            ...anchorAttrs,
            ...a
          },
          className: 'anchor'
        })
      })
      group.addShape('text', {
        attrs: {
          y: 0,
          x: 0,
          textAlign: 'center',
          textBaseline: 'middle',
          text: cfg.label,
          fill: '#565A5D',
        },
        draggable: true,
      });
      return rect
    }
  }

}, 'beginNode');
//
const setState = (name: any, value: any, item: any) => {
  const group = item.getContainer();
  //item.enableCapture(false);
  const shape = group.get('children')[0]; // 顺序根据 draw 时确定
  // if (name === 'active') {
  //   if (value) {
  //     shape.attr('stroke', 'red');
  //   } else {
  //     shape.attr('stroke', '#333');
  //   }
  // }
  if (name === 'selected') {
    if (value) {
      shape.attr('stroke', '#1f6DED');

    } else {
      shape.attr('stroke', '#8C8C8C');
    }
  }
  if (name === 'error') {
    if (value) {
      shape.attr('stroke', 'red');
    } else {
      shape.attr('stroke', '#8C8C8C');
    }
  }
  graph.value.setAutoPaint(true)
}

G6.registerEdge('flow-line', {

  draw(cfg?: propoties | undefined, group?: propoties) {
    if (cfg && group && cfg.startPoint && cfg.endPoint && cfg.style && cfg.anchors) {
      const startPoint = cfg.startPoint;
      const endPoint = cfg.endPoint;
      let sourceAnchor = cfg.sourceAnchor;
      let targetAnchor = cfg.targetAnchor;
      const {
        style
      } = cfg;
      let path = [];
      // path = [
      //   ['M', startPoint.x + cfg.anchors[sourceAnchor]?.offsetX || 0, startPoint.y + cfg.anchors[sourceAnchor]?.offsetY || 0],
      //   ['L', endPoint.x, endPoint.y],
      // ];
      if (!targetAnchor && targetAnchor !== 0 || !node_dragging.value) {
        path = [
          ['M', startPoint.x + cfg.anchors[sourceAnchor]?.offsetX || 0, startPoint.y + cfg.anchors[sourceAnchor]?.offsetY || 0],
          ['L', endPoint.x, endPoint.y],
        ];
      } else {
        path = getPath(startPoint, endPoint, sourceAnchor, targetAnchor, cfg) || [
          ['M', startPoint.x + cfg.anchors[sourceAnchor]?.offsetX || 0, startPoint.y + cfg.anchors[sourceAnchor]?.offsetY || 0],
          ['L', endPoint.x + cfg.anchors[targetAnchor]?.offsetX || 0, endPoint.y + cfg.anchors[targetAnchor]?.offsetY]];
      }

      const shape = group.addShape('path', {
        attrs: {
          stroke: '#8C8C8C',
          // endArrow: style.endArrow,  // 需要箭头可以自己配置箭头 有开始箭头和结束箭头
          path: path,
          endArrow: {
            path: G6.Arrow.triangle(5, 5, 0), // 使用内置箭头路径函数，参数为箭头的 宽度、长度、偏移量（默认为 0，与 d 对应）
            d: 0,
            fill: '#8C8C8C',
            opacity: 1,
            lineWidth: 1,
          },
          lineWidth: 1,
          lineAppendWidth: 20,
        },
      });
      //shape.set('capture', false);
      return shape;
    }
  },
  afterDraw(cfg?: ModelConfig | undefined, group?: propoties, keyShape?: propoties) {
    //   if (cfg && group) {
    //     const shape = group.get('children')[0];
    //     const startPoint = shape.getPoint(0);
    //     //创建节点之间的圆圈，并为每一个设置样式
    //     const circle = group.addShape('circle', {
    //       attrs: {
    //         x: startPoint.x,
    //         y: startPoint.y,
    //         fill: '#cbdaff',
    //         r: 4, //圆圈大小
    //       },
    //       name: 'circle-shape',
    //     });
    //     // 实现动态效果，从线的开始滑到结束
    //     circle.animate(
    //       (ratio: any) => {
    //         const tmpPoint = shape.getPoint(ratio);
    //         return {
    //           x: tmpPoint.x,
    //           y: tmpPoint.y,

    //         };
    //       }, {
    //       repeat: 1, //动画是否重复
    //       duration: 3000, //一次动画持续时长
    //     },
    //     );
    //     circle.set('capture', false)
    //   }

    if (keyShape && group && cfg) {
      var center = keyShape.getPoint(0.5);
      const text = group.addShape('text', {
        attrs: {
          x: center.x,
          y: center.y,
          fill: '#565A5D',
          textAlign: 'center',
          text: cfg.label
        },
        name: 'text-shape'
      });

      //text.set('capture', false);
    }

  },
  // 设置状态
  setState,
});

const init = () => {
  if (graph.value) {
    graph.value.destroy();
  }
  let Grid = new G6.Grid();
  const width = document.querySelector('#mountNode_readOnly')?.clientWidth || 800;
  const height = document.querySelector('#mountNode_readOnly')?.clientHeight || 1000;
  graph.value = new G6.Graph({
    container: "mountNode_readOnly", // 指定挂载点
    // 画布宽高
    width: width,
    height: height,
    plugins: [Grid],
    maxZoom: 1,
    //minZoom: 0.001,
    //fitCenter: true,
    //fitViewPadding: [20, 200, 0, 200],
    fitView: true,

    defaultNode: {
      //type: 'auditNode',
      style: {
        cursor: "pointer",
      },
    },
    // layout: {
    //   type: 'dagre',
    //   controlPoints: true,
    //   // ... 其他配置
    // },
    //边的样式配置
    defaultEdge: {
      type: 'flow-line',
      //边样式配置
      style: {
        stroke: "#409EFF", // 边描边颜色
        endArrow: {
          path: G6.Arrow.triangle(5, 5, 0), // 使用内置箭头路径函数，参数为箭头的 宽度、长度、偏移量（默认为 0，与 d 对应）
          d: 0,
          fill: '#8C8C8C',
          opacity: 1,
          // lineWidth: 1,
        },
      },
      labelCfg: {
        position: 'center'
      },
      anchors: [
        { offsetX: -80, offsetY: 0 },
        { offsetX: 0, offsetY: 24 },
        { offsetX: 80, offsetY: 0 },
        { offsetX: 0, offsetY: -24 }
      ]
    },

    modes: {
      readonly: ['drag-canvas'],
      default: ['drag-canvas',
        // shouldBegin(e) {
        //   const item = e.item
        //   const err = item?.getModel().errors
        //   if (!(err instanceof Array && err.length)) return false
        //   return true
        // },
        // shouldUpdate(e) {

        //   if (e.type == "mousemove") {
        //     return false
        //   }
        //   console.log(1111, e);
        //   // 如果移动到节点文本上显示，不是文本上不显示
        //   // if (e.target. !== 'text') {
        //   //   return false
        //   // }
        //   return true
        // }
      ],
      edit: ['drag-add-line'],
      line: ['click-add-line'],
      polyline: ['click-add-line']
    },
  });
  //读取数据
  //graph.het('canvas').set('localFresh', false);
  console.log(flow_data.value, 8888)
  graph.value.data(flow_data.value);
  // 渲染图
  graph.value.render();
  // 进入节点显示锚点
  // 拖拽锚点画线
  //registerBehavior();
  //registerEdge();
  //listening();
}
const onSelectItem = (item: propoties) => {
  const nodes = graph.value.findAllByState('node', 'click');
  if (nodes instanceof Array && nodes.length) {
    nodes.forEach(node => {
      //if (item._cfg.id != node._cfg.id) {
      graph.value.setItemState(node, 'click', false);
      //}
    })
  }
  const edges = graph.value.findAllByState('edge', 'selected')
  if (edges instanceof Array && edges.length) {
    edges.forEach(edge => {
      graph.value.clearItemStates(edge)
    })
  }
}




// 动态判断普通情况的折线轨迹
const getPath = (startPoint: propoties, endPoint: propoties, sourceAnchor: number, targetAnchor: number, cfg: propoties) => {
  const nodeName = graph.value.findById(cfg.target)._cfg.currentShape;
  let anchors = [];
  let SAoffsetX = cfg.anchors[sourceAnchor]?.offsetX || 0;
  let SAoffsetY = cfg.anchors[sourceAnchor]?.offsetY || 0;
  let TAffsetX = cfg.anchors[targetAnchor]?.offsetX || 0;
  let TAffsetyY = cfg.anchors[targetAnchor]?.offsetY || 0;
  if (nodeName == 'beginNode') {
    anchors = [
      { offsetX: -25, offsetY: 0 },
      { offsetX: 0, offsetY: 25 },
      { offsetX: 25, offsetY: 0 },
      { offsetX: 0, offsetY: -25 }
    ]
    TAffsetX = anchors[targetAnchor]?.offsetX;
    TAffsetyY = anchors[targetAnchor]?.offsetY;
  } else if (nodeName == 'endNode') {
    anchors = [
      { offsetX: -38, offsetY: 0 },
      { offsetX: 0, offsetY: 24 },
      { offsetX: 38, offsetY: 0 },
      { offsetX: 0, offsetY: -24 }
    ]
    TAffsetX = anchors[targetAnchor]?.offsetX;
    TAffsetyY = anchors[targetAnchor]?.offsetY;
  }

  let offsetX = 0;
  //let type = 0;
  let offsetX2 = 0;
  if (sourceAnchor == 0 || sourceAnchor == 2) {
    if (targetAnchor == 2) {
      if (sourceAnchor == 2) {
        offsetX = Math.abs(endPoint.x - startPoint.x) + 30;
        if (offsetX > 30) {
          offsetX = 30;
        }
        return [
          ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
          ['L', startPoint.x + SAoffsetX + offsetX, startPoint.y + SAoffsetY],
          ['L', startPoint.x + SAoffsetX + offsetX, endPoint.y + TAffsetyY],
          ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
        ]
      } else if (sourceAnchor == 0) {
        offsetX = Math.abs(endPoint.x - startPoint.x) + 20;
        offsetX2 = -Math.abs(endPoint.x - startPoint.x) - 20;
        if (endPoint.x + SAoffsetX < startPoint.x + TAffsetX - 180) { // 120是图形的宽度
          offsetX = -Math.abs(endPoint.x - startPoint.x) / 4 - 20;
          if (offsetX <= -30) {
            offsetX = -30
          }
          return [
            ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX, startPoint.y + SAoffsetY],
            ['L', endPoint.x + TAffsetX - offsetX, endPoint.y + TAffsetyY],
            ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
          ]
        } else {
          return [
            ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX2, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX2, (startPoint.y + SAoffsetY + endPoint.y + TAffsetyY) / 2],
            ['L', endPoint.x + TAffsetX + offsetX, (startPoint.y + SAoffsetY + endPoint.y + TAffsetyY) / 2],
            ['L', endPoint.x + TAffsetX + offsetX, endPoint.y + TAffsetyY],
            ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
          ]
        }

      }

    } else if (targetAnchor == 0) {
      if (sourceAnchor == 2) {
        offsetX = Math.abs(endPoint.x - startPoint.x) + 20;
        offsetX2 = -Math.abs(endPoint.x - startPoint.x) - 20;
        if (endPoint.x + SAoffsetX - 180 > startPoint.x + TAffsetX) {
          offsetX = Math.abs(endPoint.x - startPoint.x) / 4 + 20;
          if (offsetX >= 30) {
            offsetX = 30
          }
          return [
            ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX, startPoint.y + SAoffsetY],
            ['L', endPoint.x + TAffsetX - offsetX, endPoint.y + TAffsetyY],
            ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
          ]
        } else {
          return [
            ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX, startPoint.y + SAoffsetY],
            ['L', startPoint.x + SAoffsetX + offsetX, (startPoint.y + SAoffsetY + endPoint.y + TAffsetyY) / 2],
            ['L', endPoint.x + TAffsetX + offsetX2, (startPoint.y + SAoffsetY + endPoint.y + TAffsetyY) / 2],
            ['L', endPoint.x + TAffsetX + offsetX2, endPoint.y + TAffsetyY],
            ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
          ]
        }

      }
      else if (sourceAnchor == 0) {
        offsetX = -Math.abs(endPoint.x - startPoint.x) - 25;
        nodeName == 'beginNode' ? offsetX = offsetX - 59 : '';
        nodeName == 'endNode' ? offsetX = offsetX - 45 : '';
        return [
          ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
          ['L', endPoint.x + TAffsetX + offsetX, startPoint.y + SAoffsetY],
          ['L', endPoint.x + TAffsetX + offsetX, endPoint.y + TAffsetyY],
          ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
        ]
      }

    } else if (targetAnchor == 1) {
      //type = 1;
      if (sourceAnchor == 2) {
        offsetX = Math.abs(endPoint.x - startPoint.x) + 30;
      } else if (sourceAnchor == 0) {
        offsetX = -Math.abs(endPoint.x - startPoint.x) - 30;
      }
      return [
        ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
        ['L', startPoint.x + SAoffsetX + offsetX, startPoint.y + SAoffsetY],
        ['L', startPoint.x + SAoffsetX + offsetX, (startPoint.y + SAoffsetY + endPoint.y + TAffsetyY) / 2],
        ['L', endPoint.x + TAffsetX, (startPoint.y + SAoffsetY + endPoint.y + TAffsetyY) / 2],
        ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
      ]
    } else if (targetAnchor == 3) {
      //type = 1;
      if (sourceAnchor == 2) {
        offsetX = Math.abs(endPoint.x - startPoint.x) + 30;
      } else if (sourceAnchor == 0) {
        offsetX = -Math.abs(endPoint.x - startPoint.x) - 30;
      }
      return [
        ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
        ['L', startPoint.x + SAoffsetX + offsetX, startPoint.y + SAoffsetY],
        ['L', startPoint.x + SAoffsetX + offsetX, endPoint.y + TAffsetyY - 30],
        ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY - 30],
        ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
      ]
    }
  } else {
    return [
      ['M', startPoint.x + SAoffsetX, startPoint.y + SAoffsetY],
      ['L', endPoint.x + TAffsetX, endPoint.y + TAffsetyY],
    ]
  }

}


</script>

<style lang="scss">
#mountNode_readOnly {
  width: 100%;
  height: 100%;
  overflow: scroll;
}

.anchor:hover {
  fill: red;
  border: 2px solid #052e05;
}


.edgeGroup {
  z-index: 1000;
}
</style>
